package com.haorui.lygyd.authority.provider;

import com.haorui.base.core.exception.BusinessException;
import com.haorui.base.core.exception.NoPermissionsException;
import com.haorui.base.core.utils.BeanUtil;
import com.haorui.base.system.entity.Account;
import com.haorui.base.system.entity.PermissionsEntity;
import com.haorui.base.system.enumerate.AccountType;
import com.haorui.base.system.service.AccountService;
import com.haorui.lygyd.authority.authentication.AccountAuthenticationToken;
import com.haorui.lygyd.authority.authentication.MemberAuthenticationToken;
import com.haorui.lygyd.authority.authentication.PermsAuthenticationToken;
import com.haorui.lygyd.authority.dto.AccountAuthDto;
import com.haorui.lygyd.authority.dto.AuthMember;
import com.haorui.lygyd.authority.jwt.JwtTokenUtil;
import com.haorui.lygyd.employeemanager.entity.MemberEntity;
import com.haorui.lygyd.employeemanager.service.MemberService;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.www.NonceExpiredException;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author 陈刚
 * @version 1.0
 * @project znsm
 * @package com.haorui.znsm.authority.provider
 * @createDate 2018-03-16 15:01
 * @modfiyDate
 * @function
 */
@Service
@Slf4j
public class TokenAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    JwtTokenUtil jwtTokenUtil;
    @Autowired
    AccountService accountService;
    @Autowired
    MemberService memberService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        PermsAuthenticationToken permsAuthenticationToken = (PermsAuthenticationToken) authentication;
        String tokenHead = (String) permsAuthenticationToken.getPrincipal();
        String authHeader = (String) permsAuthenticationToken.getCredentials();
        HttpServletRequest httpServletRequest = permsAuthenticationToken.getHttpServletRequest();

        if (authHeader.startsWith(tokenHead)) {
            try {
                String authToken = authHeader.substring(tokenHead.length());
                String type = jwtTokenUtil.getType(authToken);
                AccountType accountType = AccountType.getAccountTypeByCode(type);
                if (accountType != null) {
                    String userName = jwtTokenUtil.getAccountUserName(authToken);
                    Account account = accountService.findAccountByUserName(userName);
                    if (account == null) {
                        throw new UsernameNotFoundException("用户" + userName + "不存在");
                    }
                    AccountAuthenticationToken accountAuthenticationToken = new AccountAuthenticationToken(account.getUserName(), account.getPassword());
                    accountAuthenticationToken.setWebAuthenticationDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
                    AccountAuthDto accountAuthDto = new AccountAuthDto();
                    BeanUtil.beanCopy(account, accountAuthDto);
                    accountAuthenticationToken.setDetails(accountAuthDto);
                    //如果是不是管理员权限则进行权限校验
                    if (account.getAccountType() != AccountType.HOUTAIADMIN) {
                        permsAuthenticationToken = this.accountVaild(permsAuthenticationToken, authToken);
                        accountAuthenticationToken.setAuthenticated(permsAuthenticationToken.isAuthenticated());
                    } else {
                        accountAuthenticationToken.setAuthenticated(true);
                    }
                    SecurityContextHolder.getContext().setAuthentication(accountAuthenticationToken);
                } else if ("WXUSER".equals(type)) {
                    permsAuthenticationToken = this.memberVaild(permsAuthenticationToken);
                    String id = jwtTokenUtil.getId(authToken);
                    String openId = jwtTokenUtil.getOpenId(authToken);
                    MemberEntity memberEntity = memberService.findOne(id);
                    if (memberEntity == null) {
                        throw new UsernameNotFoundException("会员id：" + id + "不存在");
                    }
                    MemberAuthenticationToken memberAuthenticationToken = new MemberAuthenticationToken(memberEntity.getShouJiHaoMa(), memberEntity.getMiMa(), openId);
                    AuthMember authMember = new AuthMember();
                    BeanUtil.beanCopy(memberEntity, authMember);
                    authMember.setOpenId(openId);
                    memberAuthenticationToken.setDetails(authMember);
                    memberAuthenticationToken.setAuthenticated(permsAuthenticationToken.isAuthenticated());
                    SecurityContextHolder.getContext().setAuthentication(memberAuthenticationToken);

                } else {
                    throw new NoPermissionsException("非法用户访问！");
                }
            } catch (JwtException e) {
                throw new NonceExpiredException("授权过期,请重新登陆!");
            }

        }

        return permsAuthenticationToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {

        return PermsAuthenticationToken.class.isAssignableFrom(authentication);
    }

    private PermsAuthenticationToken memberVaild(PermsAuthenticationToken permsAuthenticationToken) {
        HttpServletRequest httpServletRequest = permsAuthenticationToken.getHttpServletRequest();
        String url = httpServletRequest.getRequestURI();
        if (!url.startsWith("/wx")) {
            permsAuthenticationToken.setAuthenticated(false);
        } else {
            permsAuthenticationToken.setAuthenticated(true);
        }
        return permsAuthenticationToken;
    }

    /**
     * 校验账号
     *
     * @param permsAuthenticationToken
     * @param authToken
     * @return
     */
    private PermsAuthenticationToken accountVaild(PermsAuthenticationToken permsAuthenticationToken, String authToken) {
        HttpServletRequest httpServletRequest = permsAuthenticationToken.getHttpServletRequest();


        try {
            String accountId = jwtTokenUtil.getId(authToken);
            String url = httpServletRequest.getRequestURI();
            permsAuthenticationToken.setAuthenticated(this.vaildPerm(accountId, url));
        } catch (BusinessException e) {
            throw new NoPermissionsException(e.getMessage());
        }

        return permsAuthenticationToken;
    }

    /**
     * 校验URL权限
     *
     * @param accountId
     * @param url
     * @return
     * @throws BusinessException
     */
    private boolean vaildPerm(String accountId, String url) throws BusinessException {
        List<PermissionsEntity> permissionsEntityList = accountService.getPermissions(accountId);
        if (url.contains("/pagelist") || url.contains("/get")) {
            return true;
        }
        for (PermissionsEntity permissionsEntity : permissionsEntityList) {
            if (permissionsEntity.getApi() == null) {
                continue;
            }
            if (url.contains(permissionsEntity.getApi())) {
                return true;
            }
        }
        log.info("用户{}访问地址：{}，未授权", accountId, url);
        return false;

    }
}
